#include "UserInterface.hpp"

#include "Camera.hpp"
#include "Timer.hpp"
#include "Context.hpp"

UIState UserInterface::g_state;

void UserInterface::initCallbacks()
{
  // keyboard callbacks
  glutKeyboardFunc(pressNormalKey);
  glutKeyboardUpFunc(releaseNormalKey);
  glutSpecialFunc(pressSpecialKey);
  glutSpecialUpFunc(releaseSpecialKey);
  
  glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
  
  // mouse callbacks
  glutMotionFunc(motionFunc); 
  glutMouseFunc(mouseFunc);
  
  //window callbacks
  glutReshapeFunc(reshapeFunc);
  
  
  //glutTimerFunc(updateViewRate, updateView, 0);
  //glutTimerFunc(refreshRate, refresh, 0);
  
}

void UserInterface::pressNormalKey(unsigned char key, int x, int y)
{ 
  //DEBUG("UI: pressNormalKey(): '%c(%d)' (%d,%d)", key, key, x, y);
  switch (key) {
    case 27 : exit(0); break; // ESC
    case 'i' :
    case 'I' : g_state.m_forwardMotion = UIState::Increasing; break;
    case 'k' :
    case 'K' : g_state.m_forwardMotion = UIState::Decreasing; break;
    case 'j' :
    case 'J' : g_state.m_sidewaysMotion = UIState::Decreasing; break;
    case 'l' :
    case 'L' : g_state.m_sidewaysMotion = UIState::Increasing; break;          
  }
  
  switch (key) {
    case 'w' :
    case 'W' : g_state.m_w = true; break;
    case 's' :
    case 'S' : g_state.m_s = true; break;
    case 'a' :
    case 'A' : g_state.m_a = true; break;
    case 'd' :
    case 'D' : g_state.m_d = true; break;
    case 'e' :
    case 'E' : g_state.m_e = true; break;
    case 'q' :
    case 'Q' : g_state.m_q = true; break;
    case 'C' :
    case 'c' : g_state.m_lights = (g_state.m_lights+1)%3; break;
    case ' ' : g_state.m_space = true; break;
  }
  /*
  if (viewStatus != 0) {
    glutTimerFunc(updateViewRate, updateView, 0);
  }
  */
  //glutTimerFunc(Timer::m_updateViewMatrixRate, Timer::updateViewMatrix, 0);
}

void UserInterface::releaseNormalKey(unsigned char key, int x, int y)
{ 
  //DEBUG("UI: releaseNormalKey(): '%c(%d)' (%d,%d)", key, key, x, y);
  switch (key) {
    case 'i' :
    case 'I' :
    case 'k' :
    case 'K' : g_state.m_forwardMotion = UIState::Stationary; break;
    case 'j' :
    case 'J' :
    case 'l' :
    case 'L' : g_state.m_sidewaysMotion = UIState::Stationary; break;
  }
  
  switch (key) {
    case 'w' :
    case 'W' : g_state.m_w = false; break;
    case 's' :
    case 'S' : g_state.m_s = false; break;
    case 'a' :
    case 'A' : g_state.m_a = false; break;
    case 'd' :
    case 'D' : g_state.m_d = false; break;
    case 'e' :
    case 'E' : g_state.m_e = false; break;
    case 'q' :
    case 'Q' : g_state.m_q = false; break;
    case ' ' : g_state.m_space = false; break;
  }
}

void UserInterface::pressSpecialKey(int key, int x, int y)
{
  //DEBUG("UI: pressSpecialKey(): '%c(%d)' (%d,%d)", key, key, x, y);
  switch (key) {
    case GLUT_KEY_UP    : g_state.m_pitch = UIState::Increasing; break;
    case GLUT_KEY_DOWN  : g_state.m_pitch = UIState::Decreasing; break;
    case GLUT_KEY_LEFT  : g_state.m_yaw = UIState::Increasing; break; 
    case GLUT_KEY_RIGHT : g_state.m_yaw = UIState::Decreasing; break;
  }
  /*
  if (viewStatus != 0) {
    glutTimerFunc(updateViewRate, updateView, 0);
  }
  */
} 

void UserInterface::releaseSpecialKey(int key, int x, int y)
{
  //DEBUG("UI: releaseSpecialKey(): '%c(%d)' (%d,%d)", key, key, x, y);
  switch (key) {
    case GLUT_KEY_UP    :
    case GLUT_KEY_DOWN  : g_state.m_pitch = UIState::Stationary; break;
    case GLUT_KEY_LEFT  :
    case GLUT_KEY_RIGHT : g_state.m_yaw = UIState::Stationary; break;
  }
}

void UserInterface::mouseFunc(int button, int state, int x, int y)
{
  //DEBUG("UI: mouseFunc(): button:%d state:%d (%d,%d)\n", button, state, x, y);
  switch (button) {
    case GLUT_RIGHT_BUTTON  :
    case GLUT_LEFT_BUTTON   :
    case GLUT_MIDDLE_BUTTON :
      break;
  }  

  
}

void UserInterface::motionFunc(int x, int y) {
  g_state.m_cursor.x = x/400.0f-1.0f;
  g_state.m_cursor.y = y/300.0f-1.0f;
  
}


void UserInterface::reshapeFunc(int x, int y) 
{  
  glViewport(0, 0, (GLsizei)x, (GLsizei)y); // Set our viewport to the size of our window
  
  g_context.m_camera->updateProjection(x, y);
}
